﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using HslCommunication.Core.Net;
using HslCommunication.LogNet;

namespace HslCommunication.Enthernet.Redis
{
	/// <summary>
	/// Redis协议的订阅操作，一个对象订阅一个或是多个频道的信息，当发生网络异常的时候，内部会进行自动重连，并恢复之前的订阅信息。<br />
	/// In the subscription operation of the Redis protocol, an object subscribes to the information of one or more channels. 
	/// When a network abnormality occurs, the internal will automatically reconnect and restore the previous subscription information.
	/// </summary>
	// Token: 0x02000106 RID: 262
	public class RedisSubscribe : NetworkXBase
	{
		/// <summary>
		/// 实例化一个发布订阅类的客户端，需要指定ip地址，端口。<br />
		/// To instantiate a publish and subscribe client, you need to specify the ip address and port.
		/// </summary>
		/// <param name="ipAddress">服务器的IP地址</param>
		/// <param name="port">服务器的端口号</param>
		// Token: 0x06001675 RID: 5749 RVA: 0x000738E8 File Offset: 0x00071AE8
		public RedisSubscribe(string ipAddress, int port)
		{
			this.endPoint = new IPEndPoint(IPAddress.Parse(ipAddress), port);
			this.keyWords = new List<string>();
		}

		/// <summary>
		/// 实例化一个发布订阅类的客户端，需要指定ip地址，端口，及订阅关键字。<br />
		/// To instantiate a publish-subscribe client, you need to specify the ip address, port, and subscription keyword.
		/// </summary>
		/// <param name="ipAddress">服务器的IP地址</param>
		/// <param name="port">服务器的端口号</param>
		/// <param name="keys">订阅关键字</param>
		// Token: 0x06001676 RID: 5750 RVA: 0x00073944 File Offset: 0x00071B44
		public RedisSubscribe(string ipAddress, int port, string[] keys)
		{
			this.endPoint = new IPEndPoint(IPAddress.Parse(ipAddress), port);
			this.keyWords = new List<string>(keys);
		}

		/// <summary>
		/// 实例化一个发布订阅类的客户端，需要指定ip地址，端口，及订阅关键字。<br />
		/// To instantiate a publish-subscribe client, you need to specify the ip address, port, and subscription keyword.
		/// </summary>
		/// <param name="ipAddress">服务器的IP地址</param>
		/// <param name="port">服务器的端口号</param>
		/// <param name="key">订阅关键字</param>
		// Token: 0x06001677 RID: 5751 RVA: 0x000739A0 File Offset: 0x00071BA0
		public RedisSubscribe(string ipAddress, int port, string key)
		{
			this.endPoint = new IPEndPoint(IPAddress.Parse(ipAddress), port);
			this.keyWords = new List<string>
			{
				key
			};
		}

		// Token: 0x06001678 RID: 5752 RVA: 0x00073A04 File Offset: 0x00071C04
		private OperateResult CreatePush()
		{
			Socket coreSocket = this.CoreSocket;
			if (coreSocket != null)
			{
				coreSocket.Close();
			}
			OperateResult<Socket> operateResult = base.CreateSocketAndConnect(this.endPoint, this.connectTimeOut);
			bool flag = !operateResult.IsSuccess;
			OperateResult result;
			if (flag)
			{
				result = operateResult;
			}
			else
			{
				bool flag2 = !string.IsNullOrEmpty(this.Password);
				if (flag2)
				{
					OperateResult operateResult2 = base.Send(operateResult.Content, RedisHelper.PackStringCommand(new string[]
					{
						"AUTH",
						this.Password
					}));
					bool flag3 = !operateResult2.IsSuccess;
					if (flag3)
					{
						return operateResult2;
					}
					OperateResult<byte[]> operateResult3 = base.ReceiveRedisCommand(operateResult.Content);
					bool flag4 = !operateResult3.IsSuccess;
					if (flag4)
					{
						return operateResult3;
					}
					string @string = Encoding.UTF8.GetString(operateResult3.Content);
					bool flag5 = !@string.StartsWith("+OK");
					if (flag5)
					{
						return new OperateResult(@string);
					}
				}
				List<string> list = this.keyWords;
				bool flag6 = list != null && list.Count > 0;
				if (flag6)
				{
					OperateResult operateResult4 = base.Send(operateResult.Content, RedisHelper.PackSubscribeCommand(this.keyWords.ToArray()));
					bool flag7 = !operateResult4.IsSuccess;
					if (flag7)
					{
						return operateResult4;
					}
				}
				this.CoreSocket = operateResult.Content;
				try
				{
					operateResult.Content.BeginReceive(new byte[0], 0, 0, SocketFlags.None, new AsyncCallback(this.ReceiveCallBack), operateResult.Content);
				}
				catch (Exception ex)
				{
					return new OperateResult(ex.Message);
				}
				result = OperateResult.CreateSuccessResult();
			}
			return result;
		}

		// Token: 0x06001679 RID: 5753 RVA: 0x00073BB4 File Offset: 0x00071DB4
		private void ReceiveCallBack(IAsyncResult ar)
		{
			Socket socket = ar.AsyncState as Socket;
			bool flag = socket != null;
			if (flag)
			{
				try
				{
					int num = socket.EndReceive(ar);
				}
				catch (ObjectDisposedException)
				{
					ILogNet logNet = base.LogNet;
					if (logNet != null)
					{
						logNet.WriteWarn("Socket Disposed!");
					}
					return;
				}
				catch (Exception ex)
				{
					this.SocketReceiveException(ex);
					return;
				}
				OperateResult<byte[]> operateResult = base.ReceiveRedisCommand(socket);
				bool flag2 = !operateResult.IsSuccess;
				if (flag2)
				{
					this.SocketReceiveException(null);
				}
				else
				{
					try
					{
						socket.BeginReceive(new byte[0], 0, 0, SocketFlags.None, new AsyncCallback(this.ReceiveCallBack), socket);
					}
					catch (Exception ex2)
					{
						this.SocketReceiveException(ex2);
						return;
					}
					OperateResult<string[]> stringsFromCommandLine = RedisHelper.GetStringsFromCommandLine(operateResult.Content);
					bool flag3 = !stringsFromCommandLine.IsSuccess;
					if (flag3)
					{
						ILogNet logNet2 = base.LogNet;
						if (logNet2 != null)
						{
							logNet2.WriteWarn(stringsFromCommandLine.Message);
						}
					}
					else
					{
						bool flag4 = stringsFromCommandLine.Content[0].ToUpper() == "SUBSCRIBE";
						if (!flag4)
						{
							bool flag5 = stringsFromCommandLine.Content[0].ToUpper() == "MESSAGE";
							if (flag5)
							{
								RedisSubscribe.RedisMessageReceiveDelegate onRedisMessageReceived = this.OnRedisMessageReceived;
								if (onRedisMessageReceived != null)
								{
									onRedisMessageReceived(stringsFromCommandLine.Content[1], stringsFromCommandLine.Content[2]);
								}
							}
							else
							{
								ILogNet logNet3 = base.LogNet;
								if (logNet3 != null)
								{
									logNet3.WriteWarn(stringsFromCommandLine.Content[0]);
								}
							}
						}
					}
				}
			}
		}

		// Token: 0x0600167A RID: 5754 RVA: 0x00073D50 File Offset: 0x00071F50
		private void SocketReceiveException(Exception ex)
		{
			bool isSuccess;
			do
			{
				bool flag = ex != null;
				if (flag)
				{
					ILogNet logNet = base.LogNet;
					if (logNet != null)
					{
						logNet.WriteException("Offline", ex);
					}
				}
				Console.WriteLine(StringResources.Language.ReConnectServerAfterTenSeconds);
				Thread.Sleep(this.reconnectTime);
				isSuccess = this.CreatePush().IsSuccess;
			}
			while (!isSuccess);
			Console.WriteLine(StringResources.Language.ReConnectServerSuccess);
		}

		// Token: 0x0600167B RID: 5755 RVA: 0x00073DC4 File Offset: 0x00071FC4
		private void AddSubTopics(string[] topics)
		{
			object obj = this.listLock;
			lock (obj)
			{
				for (int i = 0; i < topics.Length; i++)
				{
					bool flag2 = !this.keyWords.Contains(topics[i]);
					if (flag2)
					{
						this.keyWords.Add(topics[i]);
					}
				}
			}
		}

		// Token: 0x0600167C RID: 5756 RVA: 0x00073E40 File Offset: 0x00072040
		private void RemoveSubTopics(string[] topics)
		{
			object obj = this.listLock;
			lock (obj)
			{
				for (int i = 0; i < topics.Length; i++)
				{
					bool flag2 = this.keyWords.Contains(topics[i]);
					if (flag2)
					{
						this.keyWords.Remove(topics[i]);
					}
				}
			}
		}

		/// <summary>
		/// 如果Redis服务器设置了密码，此处就需要进行设置。必须在 <see cref="M:HslCommunication.Enthernet.Redis.RedisSubscribe.ConnectServer" /> 方法调用前设置。<br />
		/// If the Redis server has set a password, it needs to be set here. Must be set before the <see cref="M:HslCommunication.Enthernet.Redis.RedisSubscribe.ConnectServer" /> method is called.
		/// </summary>
		// Token: 0x17000507 RID: 1287
		// (get) Token: 0x0600167D RID: 5757 RVA: 0x00073EB8 File Offset: 0x000720B8
		// (set) Token: 0x0600167E RID: 5758 RVA: 0x00073EC0 File Offset: 0x000720C0
		public string Password { get; set; }

		/// <summary>
		/// 获取或设置当前连接超时时间，主要对 <see cref="M:HslCommunication.Enthernet.Redis.RedisSubscribe.ConnectServer" /> 方法有影响，默认值为 5000，也即是5秒。<br />
		/// Get or set the current connection timeout period, which mainly affects the <see cref="M:HslCommunication.Enthernet.Redis.RedisSubscribe.ConnectServer" /> method. The default value is 5000, which is 5 seconds.
		/// </summary>
		// Token: 0x17000508 RID: 1288
		// (get) Token: 0x0600167F RID: 5759 RVA: 0x00073EC9 File Offset: 0x000720C9
		// (set) Token: 0x06001680 RID: 5760 RVA: 0x00073ED1 File Offset: 0x000720D1
		public int ConnectTimeOut
		{
			get
			{
				return this.connectTimeOut;
			}
			set
			{
				this.connectTimeOut = value;
			}
		}

		/// <summary>
		/// 从Redis服务器订阅一个或多个主题信息<br />
		/// Subscribe to one or more topics from the redis server
		/// </summary>
		/// <param name="topic">主题信息</param>
		/// <returns>订阅结果</returns>
		// Token: 0x06001681 RID: 5761 RVA: 0x00073EDA File Offset: 0x000720DA
		public OperateResult SubscribeMessage(string topic)
		{
			return this.SubscribeMessage(new string[]
			{
				topic
			});
		}

		/// <inheritdoc cref="M:HslCommunication.Enthernet.Redis.RedisSubscribe.SubscribeMessage(System.String)" />
		// Token: 0x06001682 RID: 5762 RVA: 0x00073EEC File Offset: 0x000720EC
		public OperateResult SubscribeMessage(string[] topics)
		{
			bool flag = topics == null;
			OperateResult result;
			if (flag)
			{
				result = OperateResult.CreateSuccessResult();
			}
			else
			{
				bool flag2 = topics.Length == 0;
				if (flag2)
				{
					result = OperateResult.CreateSuccessResult();
				}
				else
				{
					bool flag3 = this.CoreSocket == null;
					if (flag3)
					{
						OperateResult operateResult = this.ConnectServer();
						bool flag4 = !operateResult.IsSuccess;
						if (flag4)
						{
							return operateResult;
						}
					}
					OperateResult operateResult2 = base.Send(this.CoreSocket, RedisHelper.PackSubscribeCommand(topics));
					bool flag5 = !operateResult2.IsSuccess;
					if (flag5)
					{
						result = operateResult2;
					}
					else
					{
						this.AddSubTopics(topics);
						result = OperateResult.CreateSuccessResult();
					}
				}
			}
			return result;
		}

		/// <summary>
		/// 取消订阅多个主题信息，取消之后，当前的订阅数据就不在接收到。<br />
		/// Unsubscribe from multiple topic information. After cancellation, the current subscription data will not be received.
		/// </summary>
		/// <param name="topics">主题信息</param>
		/// <returns>取消订阅结果</returns>
		// Token: 0x06001683 RID: 5763 RVA: 0x00073F80 File Offset: 0x00072180
		public OperateResult UnSubscribeMessage(string[] topics)
		{
			bool flag = this.CoreSocket == null;
			if (flag)
			{
				OperateResult operateResult = this.ConnectServer();
				bool flag2 = !operateResult.IsSuccess;
				if (flag2)
				{
					return operateResult;
				}
			}
			OperateResult operateResult2 = base.Send(this.CoreSocket, RedisHelper.PackUnSubscribeCommand(topics));
			bool flag3 = !operateResult2.IsSuccess;
			OperateResult result;
			if (flag3)
			{
				result = operateResult2;
			}
			else
			{
				this.RemoveSubTopics(topics);
				result = OperateResult.CreateSuccessResult();
			}
			return result;
		}

		/// <summary>
		/// 取消已经订阅的主题信息
		/// </summary>
		/// <param name="topic">主题信息</param>
		/// <returns>取消订阅结果</returns>
		// Token: 0x06001684 RID: 5764 RVA: 0x00073FF0 File Offset: 0x000721F0
		public OperateResult UnSubscribeMessage(string topic)
		{
			return this.UnSubscribeMessage(new string[]
			{
				topic
			});
		}

		/// <summary>
		/// 连接Redis的服务器，如果已经初始化了订阅的Topic信息，那么就会直接进行订阅操作。
		/// </summary>
		/// <returns>是否创建成功</returns>
		// Token: 0x06001685 RID: 5765 RVA: 0x00074004 File Offset: 0x00072204
		public OperateResult ConnectServer()
		{
			return this.CreatePush();
		}

		/// <summary>
		/// 关闭消息推送的界面
		/// </summary>
		// Token: 0x06001686 RID: 5766 RVA: 0x0007401C File Offset: 0x0007221C
		public void ConnectClose()
		{
			Socket coreSocket = this.CoreSocket;
			if (coreSocket != null)
			{
				coreSocket.Close();
			}
			object obj = this.listLock;
			lock (obj)
			{
				this.keyWords.Clear();
			}
		}

		/// <summary>
		/// 当接收到Redis订阅的信息的时候触发
		/// </summary>
		// Token: 0x14000035 RID: 53
		// (add) Token: 0x06001687 RID: 5767 RVA: 0x0007407C File Offset: 0x0007227C
		// (remove) Token: 0x06001688 RID: 5768 RVA: 0x000740B4 File Offset: 0x000722B4
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public event RedisSubscribe.RedisMessageReceiveDelegate OnRedisMessageReceived;

		/// <inheritdoc />
		// Token: 0x06001689 RID: 5769 RVA: 0x000740E9 File Offset: 0x000722E9
		public override string ToString()
		{
			return string.Format("RedisSubscribe[{0}]", this.endPoint);
		}

		// Token: 0x04000528 RID: 1320
		private IPEndPoint endPoint;

		// Token: 0x04000529 RID: 1321
		private List<string> keyWords = null;

		// Token: 0x0400052A RID: 1322
		private object listLock = new object();

		// Token: 0x0400052B RID: 1323
		private int reconnectTime = 10000;

		// Token: 0x0400052C RID: 1324
		private int connectTimeOut = 5000;

		/// <summary>
		/// 当接收到Redis订阅的信息的时候触发<br />
		/// Triggered when receiving Redis subscription information
		/// </summary>
		/// <param name="topic">主题信息</param>
		/// <param name="message">数据信息</param>
		// Token: 0x020006C4 RID: 1732
		// (Invoke) Token: 0x06002FC2 RID: 12226
		public delegate void RedisMessageReceiveDelegate(string topic, string message);
	}
}
